In this document, we summarize the logic, structure, and results of the analyses.

  1. Effect of ecological factors on nematode load.
  2. Phylogenetic signal of encapsulations in the Naesiotus radiation.
  3. Analysis of nematode sequenced DNA.



1. Effect of ecological factors on nematode load



We investigate the impact of various ecological factors on nematode load in snails within the Naesiotus radiation. Species exhibit differences in shell brightness, which are linked to distinct habitats and island age (Kraemer et al. 2019). It is hypothesized that snails evolve brighter shells to mitigate abiotic pressure from insolation, aiding in thermoregulation. Kraemer et al. (2019) documented that snails on older islands and in humid habitats typically have darker shells that blend with their backgrounds, potentially due to biotic pressure from predatory birds. This suggests a trade-off between abiotic and biotic selection forces influencing shell brightness, with other factors such as snail behavior playing a role in this complex dynamic.

We hypothesize that snail behavior, microhabitat, and island characteristics influence nematode load in snail shells. Nematodes may be more abundant and diverse in ground-level and humid habitats. The age of an island correlates with community maturity, which could affect nematode abundance and diversity in various ways. For example, older islands may support a higher diversity of nematode species due to increased time for coevolution and specialization in infecting snails. Additionally, larger island areas might promote nematode diversity by providing a wider range of habitats. While it is unclear whether shell brightness directly affects the snail’s capacity for nematode encapsulation, it is plausible given that both are influenced by the shell’s chemical structure and composition.

We test whether snails’ mean brightness, microhabitat, vegetation zone, island age and area predict the variation in encapsulated nematode loads.

We use three different datasets:

In all scripts, there are steps to correct and match names between the datasets.

The script raw_data. computes data plots:

Fig 1. Nematode counts by categories on each species and island
Fig 1. Nematode counts by categories on each species and island
Fig 2. (A) shows the mean brightness for each snail species in the X asis and the nematode counts in the Y axis, with individual counts in black and means for each species in red. (B) shows the data for habitat for each snail species, and the black points show the mean load. (C) as in B for vegetation zone data. (D) Nematode counts and mean for the different species within each island as a function of island age. (E) as in D for island area. (E) boxplot showing the distribution of mean load data of the species within each island
Fig 2. (A) shows the mean brightness for each snail species in the X asis and the nematode counts in the Y axis, with individual counts in black and means for each species in red. (B) shows the data for habitat for each snail species, and the black points show the mean load. (C) as in B for vegetation zone data. (D) Nematode counts and mean for the different species within each island as a function of island age. (E) as in D for island area. (E) boxplot showing the distribution of mean load data of the species within each island



We first run a model for each predictor separately, and then build a join model combining them all.



1.1. Load ~ Brightness



47 \(i\) species with load data and 23 \(k\) species with brightness data

We assume a negative slope, with brighter shells showing less load, based on our intuition of the system and the raw data



Brightness Model

\[ \log(\text{brightness}_k) \sim \mathcal{N}(\mu_{\text{bright}, \text{species}_k}, \sigma_{\text{bright}}) \]

Nematode Load Model

\[ \lambda_j = \alpha + \beta \mu_{\text{bright}, j} \] \[ \text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i})) \]



Stan



data {
  int<lower=0> N_nem;               // Number of observations for nematode load
  int<lower=0> N_bright;            // Number of observations for brightness
  array[N_nem] int<lower=0, upper=100> load;  // Nematode load counts
  vector[N_bright] brightness;       // Brightness scores
  int<lower=0> N_sp_nem;             // Number of species in the nematode data
  // int<lower=0> N_sp_bright;          // Number of species in the brightness data
  array[N_nem] int<lower=1, upper=N_sp_nem> species_i;   // New species id for load dataset
  array[N_bright] int<lower=1, upper=N_sp_nem> species_k; // New species id for brightness dataset
}

transformed data{
  
  vector[N_bright] log_brightness;
  log_brightness = log(brightness);
  
}


parameters {
  real intercept;
  real<upper=0> slope_bright;
  vector[N_sp_nem] mu_bright;       // Mean brightness for each species
  real<lower=0> sigma_bright; // Standard deviation of brightness for each species
}

model {
  vector[N_sp_nem] lambda;
  
  // Priors
  intercept ~ normal(0, 1);
  slope_bright ~ normal(0, 1);
  mu_bright ~ normal(5, 2);
  sigma_bright ~ exponential(1);
  
  // Model brightness
  log_brightness ~ normal(mu_bright[species_k], sigma_bright);
  
  // Model nematode load
  lambda = intercept + slope_bright * mu_bright;
  load ~ poisson_log(lambda[species_i]); //T[ ,100];
}

generated quantities {
  array[N_bright] real predicted_brightness;  // Predicted brightness
  array[N_nem] int predicted_load;  // Predicted nematode load
  
  
  
  for (n in 1:N_nem) {
    predicted_load[n] = poisson_log_rng(intercept + slope_bright * mu_bright[species_i[n]]);
  }
  
  
  for (b in 1:N_bright) {
    predicted_brightness[b] = exp(normal_rng(mu_bright[species_k[b]], sigma_bright));
  }
  
}



Posteriors



Fig 3. Parameter posterior distributions for Load ~ brightness model
Fig 3. Parameter posterior distributions for Load ~ brightness model



Predictive accuracy



Fig 4. Predictive accuracy for Load ~ brightness model. (A) Predictions for load data. (B) Predictions for brightness data
Fig 4. Predictive accuracy for Load ~ brightness model. (A) Predictions for load data. (B) Predictions for brightness data




1.2. Load ~ habitat



47 \(i\) species with load data and 30 \(h\) species with brightness data We assume a negative slope, with arboreous snails showing less load (terrestrial coded as 0, arboreous as 1)


Habitat Model

\[ \text{habitat}_h \sim \text{Bernoulli}(\text{habitat\_prob}_{\text{species}_h}) \]

Nematode Load Model

\[ \lambda_j = \text{intercept} + \text{slope\_habitat} \times \text{habitat\_prob} \] \[ \text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i})) \]

Stan

data {
  int<lower=0> N_nem;               // Number of observations for nematode load
  int<lower=0> N_habitat;           // Number of observations for habitat
  array[N_nem] int<lower=0, upper=100> load;  // Nematode load counts
  array[N_habitat] int<lower=0, upper=1> habitat; // Habitat: 0 for terrestrial, 1 for arboreal
  int<lower=0> N_sp_nem;             // Number of species in the nematode data
  array[N_nem] int<lower=1, upper=N_sp_nem> species_i;   // New species id for load dataset
  array[N_habitat] int<lower=1, upper=N_sp_nem> species_h; // New species id for habitat dataset
}

parameters {
  real intercept;
  real<upper=0> slope_habitat;
  vector<lower=0, upper=1>[N_sp_nem] habitat_prob;  // Habitat probability for each species
}

model {
  vector[N_sp_nem] lambda;
  
  // Priors
  intercept ~ normal(0, 1);
  slope_habitat ~ normal(0, 1);
  habitat_prob ~ beta(2, 2);  // Prior for habitat probabilities
  
  // Model habitat
  habitat ~ bernoulli(habitat_prob[species_h]);
  
  // Model nematode load
  lambda = intercept + slope_habitat * habitat_prob;
  load ~ poisson_log(lambda[species_i]);
}

generated quantities {
  array[N_habitat] real predicted_habitat;  // Predicted habitat probabilities
  array[N_nem] int predicted_load;  // Predicted nematode load
  
  for (n in 1:N_nem) {
    predicted_load[n] = poisson_log_rng(intercept + slope_habitat * habitat_prob[species_i[n]]);
  }
  
  for (h in 1:N_habitat) {
    predicted_habitat[h] = bernoulli_rng(habitat_prob[species_h[h]]);
  }
}

Posteriors



Fig 5. Parameter posterior distributions for Load ~ habitat model
Fig 5. Parameter posterior distributions for Load ~ habitat model



Predictive accuracy



Fig 6. Predictive accuracy for Load ~ habitat model. (A) Predictions for load data. (B) Predictions for habitat data
Fig 6. Predictive accuracy for Load ~ habitat model. (A) Predictions for load data. (B) Predictions for habitat data




1.3. Load ~ vegetation zone



47 \(i\) species with load data and 26 \(v\) species with brightness data We assume a negative slope, with snails inhabiting arid zones showing less load (humid coded as 0, arid as 1)


Vegetation Zone Model

\[ \text{vegetation}_v \sim \text{Bernoulli}(\text{vegetation\_prob}_{\text{species}_v}) \]

Nematode Load Model

\[ \lambda_j = \text{intercept} + \text{slope\_vegetation} \times \text{vegetation\_prob} \] \[ \text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i})) \]

Stan

data {
  int<lower=0> N_nem;               // Number of observations for nematode load
  int<lower=0> N_veg;               // Number of observations for vegetation zone
  array[N_nem] int<lower=0, upper=100> load;  // Nematode load counts
  array[N_veg] int<lower=0, upper=1> vegetation; // Vegetation zone: 0 for humid, 1 for arid
  int<lower=0> N_sp_nem;             // Number of species in the nematode data
  array[N_nem] int<lower=1, upper=N_sp_nem> species_i;   // New species id for load dataset
  array[N_veg] int<lower=1, upper=N_sp_nem> species_v; // New species id for vegetation dataset
}

parameters {
  real intercept;
  real<upper=0> slope_vegetation;
  vector<lower=0, upper=1>[N_sp_nem] vegetation_prob;  // Vegetation probability for each species
}

model {
  vector[N_sp_nem] lambda;
  
  // Priors
  intercept ~ normal(0, 1);
  slope_vegetation ~ normal(0, 1);
  vegetation_prob ~ beta(2, 2);  // Prior for vegetation probabilities
  
  // Model vegetation zone
  vegetation ~ bernoulli(vegetation_prob[species_v]);
  
  // Model nematode load
  lambda = intercept + slope_vegetation * vegetation_prob;
  load ~ poisson_log(lambda[species_i]);
}

generated quantities {
  array[N_veg] real predicted_vegetation;  // Predicted vegetation probabilities
  array[N_nem] int predicted_load;  // Predicted nematode load
  
  for (n in 1:N_nem) {
    predicted_load[n] = poisson_log_rng(intercept + slope_vegetation * vegetation_prob[species_i[n]]);
  }
  
  for (v in 1:N_veg) {
    predicted_vegetation[v] = bernoulli_rng(vegetation_prob[species_v[v]]);
  }
}

Posteriors



Fig 7. Parameter posterior distributions for Load ~ vegetation model

Predictive accuracy



Fig 8. Predictive accuracy for Load ~ vegetation model. (A) Predictions for load data. (B) Predictions for vegetation data
Fig 8. Predictive accuracy for Load ~ vegetation model. (A) Predictions for load data. (B) Predictions for vegetation data




1.3. Load ~ island age and area

Nematode Load Model

\[ \lambda_i = \text{intercept} + \text{slope\_age} \times \text{island\_age}_i + \text{slope\_area} \times \log(\text{island\_area}_i) \] \[ \text{load}_i \sim \text{Poisson}(\exp(\lambda_i)) \]

Stan

data {
  int<lower=0> N_nem;                      // Number of observations
  array[N_nem] int<lower=0, upper=100> load;  // Nematode load counts
  vector[N_nem] island_age;               // Island age for each observation
  vector[N_nem] island_area;            // Island area for each observation
}

transformed data {
  vector[N_nem] log_island_area;
  log_island_area = log(island_area);  // Log-transform island area
}

parameters {
  real intercept;
  real slope_age;                      // Slope for island age
  real slope_area;                     // Slope for log-transformed island area
}

model {
  vector[N_nem] lambda;
  
  // Priors
  intercept ~ normal(0, 1);
  slope_age ~ normal(0, 1);
  slope_area ~ normal(0, 1);
  
  // Linear predictor
  lambda = intercept + slope_age * island_age + slope_area * log_island_area;
  
  // Model
  load ~ poisson_log(lambda); 
}

generated quantities {
  array[N_nem] int predicted_load;  // Predicted nematode load
  
  for (n in 1:N_nem) {
    predicted_load[n] = poisson_log_rng(intercept + slope_age * island_age[n] + slope_area * log_island_area[n]);
  }
}

Posteriors



Fig 9. Parameter posterior distributions for Load ~ vegetation model

Predictive accuracy



Fig 10. Predictive accuracy for Load ~ island age + island area model
Fig 10. Predictive accuracy for Load ~ island age + island area model




2. Phylogenetic signal of encapsulations in the Naesiotus radiation



Departuring from the most recent tree built using RAD seq, we use the RAD database to add the tip names:


Fig X. K statistic value in null distribution
Fig X. K statistic value in null distribution



We prune it to keep only the species we analyzed that match the current names:


Fig X. K statistic value in null distribution
Fig X. K statistic value in null distribution



We use the phytools package to test for phylogenetic signal.

Klomberg’s K


Phylogenetic signal K : 2.21319 MLE(sig2) : 6.27678e-05 logL(sig2) : -36.6456 P-value (based on 1000 randomizations) : 0.001


Fig X. K statistic value in null distribution
Fig X. K statistic value in null distribution


Plotting the trait value and branches using contMap() function:


Fig X. K statistic value in null distribution
Fig X. K statistic value in null distribution
LS0tDQp0aXRsZTogIkd1aWRlIGFuYWx5c2lzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KSW4gdGhpcyBkb2N1bWVudCwgd2Ugc3VtbWFyaXplIHRoZSBsb2dpYywgc3RydWN0dXJlLCBhbmQgcmVzdWx0cyBvZiB0aGUgYW5hbHlzZXMuDQoNCjEuICBFZmZlY3Qgb2YgZWNvbG9naWNhbCBmYWN0b3JzIG9uIG5lbWF0b2RlIGxvYWQuDQoyLiAgUGh5bG9nZW5ldGljIHNpZ25hbCBvZiBlbmNhcHN1bGF0aW9ucyBpbiB0aGUgTmFlc2lvdHVzIHJhZGlhdGlvbi4NCjMuICBBbmFseXNpcyBvZiBuZW1hdG9kZSBzZXF1ZW5jZWQgRE5BLg0KDQo8YnI+IDxicj4NCg0KIyAxLiBFZmZlY3Qgb2YgZWNvbG9naWNhbCBmYWN0b3JzIG9uIG5lbWF0b2RlIGxvYWQNCg0KPGJyPiA8YnI+DQoNCldlIGludmVzdGlnYXRlIHRoZSBpbXBhY3Qgb2YgdmFyaW91cyBlY29sb2dpY2FsIGZhY3RvcnMgb24gbmVtYXRvZGUgbG9hZCBpbiBzbmFpbHMgd2l0aGluIHRoZSBOYWVzaW90dXMgcmFkaWF0aW9uLiBTcGVjaWVzIGV4aGliaXQgZGlmZmVyZW5jZXMgaW4gc2hlbGwgYnJpZ2h0bmVzcywgd2hpY2ggYXJlIGxpbmtlZCB0byBkaXN0aW5jdCBoYWJpdGF0cyBhbmQgaXNsYW5kIGFnZSAoS3JhZW1lciBldCBhbC4gMjAxOSkuIEl0IGlzIGh5cG90aGVzaXplZCB0aGF0IHNuYWlscyBldm9sdmUgYnJpZ2h0ZXIgc2hlbGxzIHRvIG1pdGlnYXRlIGFiaW90aWMgcHJlc3N1cmUgZnJvbSBpbnNvbGF0aW9uLCBhaWRpbmcgaW4gdGhlcm1vcmVndWxhdGlvbi4gS3JhZW1lciBldCBhbC4gKDIwMTkpIGRvY3VtZW50ZWQgdGhhdCBzbmFpbHMgb24gb2xkZXIgaXNsYW5kcyBhbmQgaW4gaHVtaWQgaGFiaXRhdHMgdHlwaWNhbGx5IGhhdmUgZGFya2VyIHNoZWxscyB0aGF0IGJsZW5kIHdpdGggdGhlaXIgYmFja2dyb3VuZHMsIHBvdGVudGlhbGx5IGR1ZSB0byBiaW90aWMgcHJlc3N1cmUgZnJvbSBwcmVkYXRvcnkgYmlyZHMuIFRoaXMgc3VnZ2VzdHMgYSB0cmFkZS1vZmYgYmV0d2VlbiBhYmlvdGljIGFuZCBiaW90aWMgc2VsZWN0aW9uIGZvcmNlcyBpbmZsdWVuY2luZyBzaGVsbCBicmlnaHRuZXNzLCB3aXRoIG90aGVyIGZhY3RvcnMgc3VjaCBhcyBzbmFpbCBiZWhhdmlvciBwbGF5aW5nIGEgcm9sZSBpbiB0aGlzIGNvbXBsZXggZHluYW1pYy4NCg0KV2UgaHlwb3RoZXNpemUgdGhhdCBzbmFpbCBiZWhhdmlvciwgbWljcm9oYWJpdGF0LCBhbmQgaXNsYW5kIGNoYXJhY3RlcmlzdGljcyBpbmZsdWVuY2UgbmVtYXRvZGUgbG9hZCBpbiBzbmFpbCBzaGVsbHMuIE5lbWF0b2RlcyBtYXkgYmUgbW9yZSBhYnVuZGFudCBhbmQgZGl2ZXJzZSBpbiBncm91bmQtbGV2ZWwgYW5kIGh1bWlkIGhhYml0YXRzLiBUaGUgYWdlIG9mIGFuIGlzbGFuZCBjb3JyZWxhdGVzIHdpdGggY29tbXVuaXR5IG1hdHVyaXR5LCB3aGljaCBjb3VsZCBhZmZlY3QgbmVtYXRvZGUgYWJ1bmRhbmNlIGFuZCBkaXZlcnNpdHkgaW4gdmFyaW91cyB3YXlzLiBGb3IgZXhhbXBsZSwgb2xkZXIgaXNsYW5kcyBtYXkgc3VwcG9ydCBhIGhpZ2hlciBkaXZlcnNpdHkgb2YgbmVtYXRvZGUgc3BlY2llcyBkdWUgdG8gaW5jcmVhc2VkIHRpbWUgZm9yIGNvZXZvbHV0aW9uIGFuZCBzcGVjaWFsaXphdGlvbiBpbiBpbmZlY3Rpbmcgc25haWxzLiBBZGRpdGlvbmFsbHksIGxhcmdlciBpc2xhbmQgYXJlYXMgbWlnaHQgcHJvbW90ZSBuZW1hdG9kZSBkaXZlcnNpdHkgYnkgcHJvdmlkaW5nIGEgd2lkZXIgcmFuZ2Ugb2YgaGFiaXRhdHMuIFdoaWxlIGl0IGlzIHVuY2xlYXIgd2hldGhlciBzaGVsbCBicmlnaHRuZXNzIGRpcmVjdGx5IGFmZmVjdHMgdGhlIHNuYWlsJ3MgY2FwYWNpdHkgZm9yIG5lbWF0b2RlIGVuY2Fwc3VsYXRpb24sIGl0IGlzIHBsYXVzaWJsZSBnaXZlbiB0aGF0IGJvdGggYXJlIGluZmx1ZW5jZWQgYnkgdGhlIHNoZWxsJ3MgY2hlbWljYWwgc3RydWN0dXJlIGFuZCBjb21wb3NpdGlvbi4NCg0KV2UgdGVzdCB3aGV0aGVyIHNuYWlscycgbWVhbiBicmlnaHRuZXNzLCBtaWNyb2hhYml0YXQsIHZlZ2V0YXRpb24gem9uZSwgaXNsYW5kIGFnZSBhbmQgYXJlYSBwcmVkaWN0IHRoZSB2YXJpYXRpb24gaW4gZW5jYXBzdWxhdGVkIG5lbWF0b2RlIGxvYWRzLg0KDQpXZSB1c2UgdGhyZWUgZGlmZmVyZW50IGRhdGFzZXRzOg0KDQotICAgKiowNGFwcmlsMjRfZGF0YWxhYioqOiBjb250YWlucyB0aGUgbmVtYXRvZGUgKmxvYWQqLCAqaXNsYW5kIGFnZSBhbmQgYXJlYSogZGF0YSAtIG5lbWF0b2RlIGNvdW50cy9pc2xhbmQgZGF0YSBwZXIgaW5kaXZpZHVhbCwgcGVyIHNuYWlsIHNwZWNpZXMuDQotICAgKiprcmFlbWVyMjAxOV9icmlnaHRuZXNzX3Njb3JlcyoqOiBjb250YWlucyB0aGUgKmJyaWdodG5lc3MqIGFuZCAqaGFiaXRhdCogZGF0YSAtIGJyaWdodG5lc3Mgc2NvcmVzIGFuZCBoYWJpdGF0IHBlciBpbmRpdmlkdWFsLCBwZXIgc25haWwgc3BlY2llcy4NCi0gICAqKkdQUyBSQUQgc25haWxzKio6IGNvbnRhaW5zIHRoZSAqdmVnZWF0aW9uIHpvbmUqIGFuZCAqaGFiaXRhdCogZGF0YSAtIHZlZ2V0YXRpb24gem9uZSBhbmQgaGFiaXRhdCBwZXIgaW5kaXZpZHVhbCwgcGVyIHNuYWlsIHNwZWNpZXMuDQoNCj4gSW4gYWxsIHNjcmlwdHMsIHRoZXJlIGFyZSBzdGVwcyB0byBjb3JyZWN0IGFuZCBtYXRjaCBuYW1lcyBiZXR3ZWVuIHRoZSBkYXRhc2V0cy4NCg0KVGhlIHNjcmlwdCBbcmF3X2RhdGEuXXtzdHlsZT0iY29sb3I6Ymx1ZSJ9IGNvbXB1dGVzIGRhdGEgcGxvdHM6DQoNCiFbRmlnIDEuIE5lbWF0b2RlIGNvdW50cyBieSBjYXRlZ29yaWVzIG9uIGVhY2ggc3BlY2llcyBhbmQgaXNsYW5kXShkX291dHB1dC9maWd1cmVzL3Jhd19kYXRhL2xvYWRfaXNsYW5kX3NwcC5wbmcpDQoNCiFbRmlnIDIuIChBKSBzaG93cyB0aGUgbWVhbiBicmlnaHRuZXNzIGZvciBlYWNoIHNuYWlsIHNwZWNpZXMgaW4gdGhlIFggYXNpcyBhbmQgdGhlIG5lbWF0b2RlIGNvdW50cyBpbiB0aGUgWSBheGlzLCB3aXRoIGluZGl2aWR1YWwgY291bnRzIGluIGJsYWNrIGFuZCBtZWFucyBmb3IgZWFjaCBzcGVjaWVzIGluIHJlZC4gKEIpIHNob3dzIHRoZSBkYXRhIGZvciBoYWJpdGF0IGZvciBlYWNoIHNuYWlsIHNwZWNpZXMsIGFuZCB0aGUgYmxhY2sgcG9pbnRzIHNob3cgdGhlIG1lYW4gbG9hZC4gKEMpIGFzIGluIEIgZm9yIHZlZ2V0YXRpb24gem9uZSBkYXRhLiAoRCkgTmVtYXRvZGUgY291bnRzIGFuZCBtZWFuIGZvciB0aGUgZGlmZmVyZW50IHNwZWNpZXMgd2l0aGluIGVhY2ggaXNsYW5kIGFzIGEgZnVuY3Rpb24gb2YgaXNsYW5kIGFnZS4gKEUpIGFzIGluIEQgZm9yIGlzbGFuZCBhcmVhLiAoRSkgYm94cGxvdCBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbiBsb2FkIGRhdGEgb2YgdGhlIHNwZWNpZXMgd2l0aGluIGVhY2ggaXNsYW5kXShkX291dHB1dC9maWd1cmVzL3Jhd19kYXRhL3Bsb3RzX2xvYWRfZWNvbC5wbmcpDQoNCjxicj4gDQo8YnI+DQoNCioqV2UgZmlyc3QgcnVuIGEgbW9kZWwgZm9yIGVhY2ggcHJlZGljdG9yIHNlcGFyYXRlbHksIGFuZCB0aGVuIGJ1aWxkIGEgam9pbiBtb2RlbCBjb21iaW5pbmcgdGhlbSBhbGwuKioNCg0KPGJyPg0KPGJyPg0KDQojIyAxLjEuIExvYWQgfiBCcmlnaHRuZXNzDQoNCjxicj4gDQo8YnI+DQoNCj4gNDcgJGkkIHNwZWNpZXMgd2l0aCBsb2FkIGRhdGEgYW5kIDIzICRrJCBzcGVjaWVzIHdpdGggYnJpZ2h0bmVzcyBkYXRhDQoNCj4gKipXZSBhc3N1bWUgYSBuZWdhdGl2ZSBzbG9wZSwgd2l0aCBicmlnaHRlciBzaGVsbHMgc2hvd2luZyBsZXNzIGxvYWQsIGJhc2VkIG9uIG91ciBpbnR1aXRpb24gb2YgdGhlIHN5c3RlbSBhbmQgdGhlIHJhdyBkYXRhKioNCg0KPGJyPiANCjxicj4NCg0KIyMjIEJyaWdodG5lc3MgTW9kZWwNCg0KJCQgDQpcbG9nKFx0ZXh0e2JyaWdodG5lc3N9X2spIFxzaW0gXG1hdGhjYWx7Tn0oXG11X3tcdGV4dHticmlnaHR9LCBcdGV4dHtzcGVjaWVzfV9rfSwgXHNpZ21hX3tcdGV4dHticmlnaHR9fSkNCiQkDQoNCiMjIyBOZW1hdG9kZSBMb2FkIE1vZGVsDQoNCiQkIA0KXGxhbWJkYV9qID0gXGFscGhhICsgXGJldGEgXG11X3tcdGV4dHticmlnaHR9LCBqfQ0KJCQgJCQgDQpcdGV4dHtsb2FkfV9pIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGV4cChcbGFtYmRhX3tcdGV4dHtzcGVjaWVzfV9pfSkpDQokJA0KDQoNCjxicj4gDQo8YnI+DQoNCiMjIyBTdGFuDQoNCjxicj4gDQo8YnI+DQoNCmBgYCBzdGFuDQpkYXRhIHsNCiAgaW50PGxvd2VyPTA+IE5fbmVtOyAgICAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIG5lbWF0b2RlIGxvYWQNCiAgaW50PGxvd2VyPTA+IE5fYnJpZ2h0OyAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIGJyaWdodG5lc3MNCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0wLCB1cHBlcj0xMDA+IGxvYWQ7ICAvLyBOZW1hdG9kZSBsb2FkIGNvdW50cw0KICB2ZWN0b3JbTl9icmlnaHRdIGJyaWdodG5lc3M7ICAgICAgIC8vIEJyaWdodG5lc3Mgc2NvcmVzDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgLy8gaW50PGxvd2VyPTA+IE5fc3BfYnJpZ2h0OyAgICAgICAgICAvLyBOdW1iZXIgb2Ygc3BlY2llcyBpbiB0aGUgYnJpZ2h0bmVzcyBkYXRhDQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfaTsgICAvLyBOZXcgc3BlY2llcyBpZCBmb3IgbG9hZCBkYXRhc2V0DQogIGFycmF5W05fYnJpZ2h0XSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfazsgLy8gTmV3IHNwZWNpZXMgaWQgZm9yIGJyaWdodG5lc3MgZGF0YXNldA0KfQ0KDQp0cmFuc2Zvcm1lZCBkYXRhew0KICANCiAgdmVjdG9yW05fYnJpZ2h0XSBsb2dfYnJpZ2h0bmVzczsNCiAgbG9nX2JyaWdodG5lc3MgPSBsb2coYnJpZ2h0bmVzcyk7DQogIA0KfQ0KDQoNCnBhcmFtZXRlcnMgew0KICByZWFsIGludGVyY2VwdDsNCiAgcmVhbDx1cHBlcj0wPiBzbG9wZV9icmlnaHQ7DQogIHZlY3RvcltOX3NwX25lbV0gbXVfYnJpZ2h0OyAgICAgICAvLyBNZWFuIGJyaWdodG5lc3MgZm9yIGVhY2ggc3BlY2llcw0KICByZWFsPGxvd2VyPTA+IHNpZ21hX2JyaWdodDsgLy8gU3RhbmRhcmQgZGV2aWF0aW9uIG9mIGJyaWdodG5lc3MgZm9yIGVhY2ggc3BlY2llcw0KfQ0KDQptb2RlbCB7DQogIHZlY3RvcltOX3NwX25lbV0gbGFtYmRhOw0KICANCiAgLy8gUHJpb3JzDQogIGludGVyY2VwdCB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfYnJpZ2h0IH4gbm9ybWFsKDAsIDEpOw0KICBtdV9icmlnaHQgfiBub3JtYWwoNSwgMik7DQogIHNpZ21hX2JyaWdodCB+IGV4cG9uZW50aWFsKDEpOw0KICANCiAgLy8gTW9kZWwgYnJpZ2h0bmVzcw0KICBsb2dfYnJpZ2h0bmVzcyB+IG5vcm1hbChtdV9icmlnaHRbc3BlY2llc19rXSwgc2lnbWFfYnJpZ2h0KTsNCiAgDQogIC8vIE1vZGVsIG5lbWF0b2RlIGxvYWQNCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfYnJpZ2h0ICogbXVfYnJpZ2h0Ow0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhW3NwZWNpZXNfaV0pOyAvL1RbICwxMDBdOw0KfQ0KDQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogIGFycmF5W05fYnJpZ2h0XSByZWFsIHByZWRpY3RlZF9icmlnaHRuZXNzOyAgLy8gUHJlZGljdGVkIGJyaWdodG5lc3MNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICANCiAgDQogIGZvciAobiBpbiAxOk5fbmVtKSB7DQogICAgcHJlZGljdGVkX2xvYWRbbl0gPSBwb2lzc29uX2xvZ19ybmcoaW50ZXJjZXB0ICsgc2xvcGVfYnJpZ2h0ICogbXVfYnJpZ2h0W3NwZWNpZXNfaVtuXV0pOw0KICB9DQogIA0KICANCiAgZm9yIChiIGluIDE6Tl9icmlnaHQpIHsNCiAgICBwcmVkaWN0ZWRfYnJpZ2h0bmVzc1tiXSA9IGV4cChub3JtYWxfcm5nKG11X2JyaWdodFtzcGVjaWVzX2tbYl1dLCBzaWdtYV9icmlnaHQpKTsNCiAgfQ0KICANCn0NCmBgYA0KPGJyPiANCjxicj4NCg0KIyMjIyBQb3N0ZXJpb3JzDQoNCjxicj4NCjxicj4NCg0KDQohW0ZpZyAzLiBQYXJhbWV0ZXIgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZm9yIExvYWQgfiBicmlnaHRuZXNzIG1vZGVsXShkX291dHB1dC9maWd1cmVzL3Bvc3Rlcmlvcl9wYXJzL2JyaWdodF9uZWdzbG9wZS5wbmcpDQoNCg0KPGJyPg0KPGJyPg0KDQojIyMjIFByZWRpY3RpdmUgYWNjdXJhY3kNCg0KPGJyPiANCjxicj4NCg0KIVtGaWcgNC4gUHJlZGljdGl2ZSBhY2N1cmFjeSBmb3IgTG9hZCB+IGJyaWdodG5lc3MgbW9kZWwuIChBKSBQcmVkaWN0aW9ucyBmb3IgbG9hZCBkYXRhLiAoQikgUHJlZGljdGlvbnMgZm9yIGJyaWdodG5lc3MgZGF0YV0oZF9vdXRwdXQvZmlndXJlcy9wcmVkaWN0aW9ucy9wcGNfbG9hZF9icmlnaHRfbmVnLnBuZykNCg0KDQoNCjxicj4gDQo8YnI+DQo8YnI+DQoNCiMjIDEuMi4gTG9hZCB+IGhhYml0YXQNCg0KPGJyPg0KPGJyPg0KDQo+IDQ3ICRpJCBzcGVjaWVzIHdpdGggbG9hZCBkYXRhIGFuZCAzMCAkaCQgc3BlY2llcyB3aXRoIGJyaWdodG5lc3MgZGF0YQ0KPiAqKldlIGFzc3VtZSBhIG5lZ2F0aXZlIHNsb3BlLCB3aXRoIGFyYm9yZW91cyBzbmFpbHMgc2hvd2luZyBsZXNzIGxvYWQgKHRlcnJlc3RyaWFsIGNvZGVkIGFzIDAsIGFyYm9yZW91cyBhcyAxKSoqDQoNCjxicj4NCg0KIyMjIyBIYWJpdGF0IE1vZGVsDQpcWyANClx0ZXh0e2hhYml0YXR9X2ggXHNpbSBcdGV4dHtCZXJub3VsbGl9KFx0ZXh0e2hhYml0YXRcX3Byb2J9X3tcdGV4dHtzcGVjaWVzfV9ofSkNClxdDQoNCiMjIyMgTmVtYXRvZGUgTG9hZCBNb2RlbA0KXFsgDQpcbGFtYmRhX2ogPSBcdGV4dHtpbnRlcmNlcHR9ICsgXHRleHR7c2xvcGVcX2hhYml0YXR9IFx0aW1lcyBcdGV4dHtoYWJpdGF0XF9wcm9ifQ0KXF0NClxbIA0KXHRleHR7bG9hZH1faSBcc2ltIFx0ZXh0e1BvaXNzb259KFxleHAoXGxhbWJkYV97XHRleHR7c3BlY2llc31faX0pKQ0KXF0NCg0KDQojIyMgU3Rhbg0KDQpgYGAgc3Rhbg0KZGF0YSB7DQogIGludDxsb3dlcj0wPiBOX25lbTsgICAgICAgICAgICAgICAvLyBOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGZvciBuZW1hdG9kZSBsb2FkDQogIGludDxsb3dlcj0wPiBOX2hhYml0YXQ7ICAgICAgICAgICAvLyBOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGZvciBoYWJpdGF0DQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MCwgdXBwZXI9MTAwPiBsb2FkOyAgLy8gTmVtYXRvZGUgbG9hZCBjb3VudHMNCiAgYXJyYXlbTl9oYWJpdGF0XSBpbnQ8bG93ZXI9MCwgdXBwZXI9MT4gaGFiaXRhdDsgLy8gSGFiaXRhdDogMCBmb3IgdGVycmVzdHJpYWwsIDEgZm9yIGFyYm9yZWFsDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc19pOyAgIC8vIE5ldyBzcGVjaWVzIGlkIGZvciBsb2FkIGRhdGFzZXQNCiAgYXJyYXlbTl9oYWJpdGF0XSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfaDsgLy8gTmV3IHNwZWNpZXMgaWQgZm9yIGhhYml0YXQgZGF0YXNldA0KfQ0KDQpwYXJhbWV0ZXJzIHsNCiAgcmVhbCBpbnRlcmNlcHQ7DQogIHJlYWw8dXBwZXI9MD4gc2xvcGVfaGFiaXRhdDsNCiAgdmVjdG9yPGxvd2VyPTAsIHVwcGVyPTE+W05fc3BfbmVtXSBoYWJpdGF0X3Byb2I7ICAvLyBIYWJpdGF0IHByb2JhYmlsaXR5IGZvciBlYWNoIHNwZWNpZXMNCn0NCg0KbW9kZWwgew0KICB2ZWN0b3JbTl9zcF9uZW1dIGxhbWJkYTsNCiAgDQogIC8vIFByaW9ycw0KICBpbnRlcmNlcHQgfiBub3JtYWwoMCwgMSk7DQogIHNsb3BlX2hhYml0YXQgfiBub3JtYWwoMCwgMSk7DQogIGhhYml0YXRfcHJvYiB+IGJldGEoMiwgMik7ICAvLyBQcmlvciBmb3IgaGFiaXRhdCBwcm9iYWJpbGl0aWVzDQogIA0KICAvLyBNb2RlbCBoYWJpdGF0DQogIGhhYml0YXQgfiBiZXJub3VsbGkoaGFiaXRhdF9wcm9iW3NwZWNpZXNfaF0pOw0KICANCiAgLy8gTW9kZWwgbmVtYXRvZGUgbG9hZA0KICBsYW1iZGEgPSBpbnRlcmNlcHQgKyBzbG9wZV9oYWJpdGF0ICogaGFiaXRhdF9wcm9iOw0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhW3NwZWNpZXNfaV0pOw0KfQ0KDQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogIGFycmF5W05faGFiaXRhdF0gcmVhbCBwcmVkaWN0ZWRfaGFiaXRhdDsgIC8vIFByZWRpY3RlZCBoYWJpdGF0IHByb2JhYmlsaXRpZXMNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX2hhYml0YXQgKiBoYWJpdGF0X3Byb2Jbc3BlY2llc19pW25dXSk7DQogIH0NCiAgDQogIGZvciAoaCBpbiAxOk5faGFiaXRhdCkgew0KICAgIHByZWRpY3RlZF9oYWJpdGF0W2hdID0gYmVybm91bGxpX3JuZyhoYWJpdGF0X3Byb2Jbc3BlY2llc19oW2hdXSk7DQogIH0NCn0NCmBgYA0KDQoNCiMjIyMgUG9zdGVyaW9ycw0KDQo8YnI+DQo8YnI+DQoNCg0KIVtGaWcgNS4gUGFyYW1ldGVyIHBvc3RlcmlvciBkaXN0cmlidXRpb25zIGZvciBMb2FkIH4gaGFiaXRhdCBtb2RlbF0oZF9vdXRwdXQvZmlndXJlcy9wb3N0ZXJpb3JfcGFycy9wb3N0ZXJpb3JfaGFiaXRhdC5wbmcpDQoNCg0KPGJyPg0KPGJyPg0KDQoNCiMjIyMgUHJlZGljdGl2ZSBhY2N1cmFjeQ0KDQo8YnI+IA0KPGJyPg0KDQohW0ZpZyA2LiBQcmVkaWN0aXZlIGFjY3VyYWN5IGZvciBMb2FkIH4gaGFiaXRhdCBtb2RlbC4gKEEpIFByZWRpY3Rpb25zIGZvciBsb2FkIGRhdGEuIChCKSBQcmVkaWN0aW9ucyBmb3IgaGFiaXRhdCBkYXRhXShkX291dHB1dC9maWd1cmVzL3ByZWRpY3Rpb25zL3BwY19sb2FkX2hhYl9uZWcucG5nKQ0KDQoNCg0KPGJyPiANCjxicj4NCjxicj4NCg0KIyMgMS4zLiBMb2FkIH4gdmVnZXRhdGlvbiB6b25lDQoNCjxicj4NCjxicj4NCg0KPiA0NyAkaSQgc3BlY2llcyB3aXRoIGxvYWQgZGF0YSBhbmQgMjYgJHYkIHNwZWNpZXMgd2l0aCBicmlnaHRuZXNzIGRhdGENCj4gKipXZSBhc3N1bWUgYSBuZWdhdGl2ZSBzbG9wZSwgd2l0aCBzbmFpbHMgaW5oYWJpdGluZyBhcmlkIHpvbmVzIHNob3dpbmcgbGVzcyBsb2FkIChodW1pZCBjb2RlZCBhcyAwLCBhcmlkIGFzIDEpKioNCg0KPGJyPg0KDQojIyMjIFZlZ2V0YXRpb24gWm9uZSBNb2RlbA0KXFsgDQpcdGV4dHt2ZWdldGF0aW9ufV92IFxzaW0gXHRleHR7QmVybm91bGxpfShcdGV4dHt2ZWdldGF0aW9uXF9wcm9ifV97XHRleHR7c3BlY2llc31fdn0pDQpcXQ0KDQojIyMjIE5lbWF0b2RlIExvYWQgTW9kZWwNClxbIA0KXGxhbWJkYV9qID0gXHRleHR7aW50ZXJjZXB0fSArIFx0ZXh0e3Nsb3BlXF92ZWdldGF0aW9ufSBcdGltZXMgXHRleHR7dmVnZXRhdGlvblxfcHJvYn0NClxdDQpcWyANClx0ZXh0e2xvYWR9X2kgXHNpbSBcdGV4dHtQb2lzc29ufShcZXhwKFxsYW1iZGFfe1x0ZXh0e3NwZWNpZXN9X2l9KSkNClxdDQoNCg0KIyMjIFN0YW4NCg0KYGBgIHN0YW4NCmRhdGEgew0KICBpbnQ8bG93ZXI9MD4gTl9uZW07ICAgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgbmVtYXRvZGUgbG9hZA0KICBpbnQ8bG93ZXI9MD4gTl92ZWc7ICAgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgdmVnZXRhdGlvbiB6b25lDQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MCwgdXBwZXI9MTAwPiBsb2FkOyAgLy8gTmVtYXRvZGUgbG9hZCBjb3VudHMNCiAgYXJyYXlbTl92ZWddIGludDxsb3dlcj0wLCB1cHBlcj0xPiB2ZWdldGF0aW9uOyAvLyBWZWdldGF0aW9uIHpvbmU6IDAgZm9yIGh1bWlkLCAxIGZvciBhcmlkDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc19pOyAgIC8vIE5ldyBzcGVjaWVzIGlkIGZvciBsb2FkIGRhdGFzZXQNCiAgYXJyYXlbTl92ZWddIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc192OyAvLyBOZXcgc3BlY2llcyBpZCBmb3IgdmVnZXRhdGlvbiBkYXRhc2V0DQp9DQoNCnBhcmFtZXRlcnMgew0KICByZWFsIGludGVyY2VwdDsNCiAgcmVhbDx1cHBlcj0wPiBzbG9wZV92ZWdldGF0aW9uOw0KICB2ZWN0b3I8bG93ZXI9MCwgdXBwZXI9MT5bTl9zcF9uZW1dIHZlZ2V0YXRpb25fcHJvYjsgIC8vIFZlZ2V0YXRpb24gcHJvYmFiaWxpdHkgZm9yIGVhY2ggc3BlY2llcw0KfQ0KDQptb2RlbCB7DQogIHZlY3RvcltOX3NwX25lbV0gbGFtYmRhOw0KICANCiAgLy8gUHJpb3JzDQogIGludGVyY2VwdCB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfdmVnZXRhdGlvbiB+IG5vcm1hbCgwLCAxKTsNCiAgdmVnZXRhdGlvbl9wcm9iIH4gYmV0YSgyLCAyKTsgIC8vIFByaW9yIGZvciB2ZWdldGF0aW9uIHByb2JhYmlsaXRpZXMNCiAgDQogIC8vIE1vZGVsIHZlZ2V0YXRpb24gem9uZQ0KICB2ZWdldGF0aW9uIH4gYmVybm91bGxpKHZlZ2V0YXRpb25fcHJvYltzcGVjaWVzX3ZdKTsNCiAgDQogIC8vIE1vZGVsIG5lbWF0b2RlIGxvYWQNCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfdmVnZXRhdGlvbiAqIHZlZ2V0YXRpb25fcHJvYjsNCiAgbG9hZCB+IHBvaXNzb25fbG9nKGxhbWJkYVtzcGVjaWVzX2ldKTsNCn0NCg0KZ2VuZXJhdGVkIHF1YW50aXRpZXMgew0KICBhcnJheVtOX3ZlZ10gcmVhbCBwcmVkaWN0ZWRfdmVnZXRhdGlvbjsgIC8vIFByZWRpY3RlZCB2ZWdldGF0aW9uIHByb2JhYmlsaXRpZXMNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX3ZlZ2V0YXRpb24gKiB2ZWdldGF0aW9uX3Byb2Jbc3BlY2llc19pW25dXSk7DQogIH0NCiAgDQogIGZvciAodiBpbiAxOk5fdmVnKSB7DQogICAgcHJlZGljdGVkX3ZlZ2V0YXRpb25bdl0gPSBiZXJub3VsbGlfcm5nKHZlZ2V0YXRpb25fcHJvYltzcGVjaWVzX3Zbdl1dKTsNCiAgfQ0KfQ0KDQpgYGANCg0KDQojIyMjIFBvc3RlcmlvcnMNCg0KPGJyPg0KPGJyPg0KDQoNCiFbRmlnIDcuIFBhcmFtZXRlciBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9ucyBmb3IgTG9hZCB+IHZlZ2V0YXRpb24gbW9kZWxdKGRfb3V0cHV0L2ZpZ3VyZXMvcG9zdGVyaW9yX3BhcnMvcG9zdGVyaW9yX3ZlZ2V0YXRpb24ucG5nKQ0KPGJyPg0KPGJyPg0KDQoNCg0KIyMjIyBQcmVkaWN0aXZlIGFjY3VyYWN5DQoNCjxicj4gDQo8YnI+DQoNCiFbRmlnIDguIFByZWRpY3RpdmUgYWNjdXJhY3kgZm9yIExvYWQgfiB2ZWdldGF0aW9uIG1vZGVsLiAoQSkgUHJlZGljdGlvbnMgZm9yIGxvYWQgZGF0YS4gKEIpIFByZWRpY3Rpb25zIGZvciB2ZWdldGF0aW9uIGRhdGFdKGRfb3V0cHV0L2ZpZ3VyZXMvcHJlZGljdGlvbnMvcHBjX2xvYWRfdmVnX25lZy5wbmcpDQoNCg0KDQo8YnI+IA0KPGJyPg0KPGJyPg0KDQoNCiMjIDEuMy4gTG9hZCB+IGlzbGFuZCBhZ2UgYW5kIGFyZWENCg0KIyMjIyBOZW1hdG9kZSBMb2FkIE1vZGVsDQoNClxbIA0KXGxhbWJkYV9pID0gXHRleHR7aW50ZXJjZXB0fSArIFx0ZXh0e3Nsb3BlXF9hZ2V9IFx0aW1lcyBcdGV4dHtpc2xhbmRcX2FnZX1faSArIFx0ZXh0e3Nsb3BlXF9hcmVhfSBcdGltZXMgXGxvZyhcdGV4dHtpc2xhbmRcX2FyZWF9X2kpDQpcXQ0KXFsgDQpcdGV4dHtsb2FkfV9pIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGV4cChcbGFtYmRhX2kpKQ0KXF0NCg0KIyMjIFN0YW4NCg0KYGBgIHN0YW4NCmRhdGEgew0KICBpbnQ8bG93ZXI9MD4gTl9uZW07ICAgICAgICAgICAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMNCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0wLCB1cHBlcj0xMDA+IGxvYWQ7ICAvLyBOZW1hdG9kZSBsb2FkIGNvdW50cw0KICB2ZWN0b3JbTl9uZW1dIGlzbGFuZF9hZ2U7ICAgICAgICAgICAgICAgLy8gSXNsYW5kIGFnZSBmb3IgZWFjaCBvYnNlcnZhdGlvbg0KICB2ZWN0b3JbTl9uZW1dIGlzbGFuZF9hcmVhOyAgICAgICAgICAgIC8vIElzbGFuZCBhcmVhIGZvciBlYWNoIG9ic2VydmF0aW9uDQp9DQoNCnRyYW5zZm9ybWVkIGRhdGEgew0KICB2ZWN0b3JbTl9uZW1dIGxvZ19pc2xhbmRfYXJlYTsNCiAgbG9nX2lzbGFuZF9hcmVhID0gbG9nKGlzbGFuZF9hcmVhKTsgIC8vIExvZy10cmFuc2Zvcm0gaXNsYW5kIGFyZWENCn0NCg0KcGFyYW1ldGVycyB7DQogIHJlYWwgaW50ZXJjZXB0Ow0KICByZWFsIHNsb3BlX2FnZTsgICAgICAgICAgICAgICAgICAgICAgLy8gU2xvcGUgZm9yIGlzbGFuZCBhZ2UNCiAgcmVhbCBzbG9wZV9hcmVhOyAgICAgICAgICAgICAgICAgICAgIC8vIFNsb3BlIGZvciBsb2ctdHJhbnNmb3JtZWQgaXNsYW5kIGFyZWENCn0NCg0KbW9kZWwgew0KICB2ZWN0b3JbTl9uZW1dIGxhbWJkYTsNCiAgDQogIC8vIFByaW9ycw0KICBpbnRlcmNlcHQgfiBub3JtYWwoMCwgMSk7DQogIHNsb3BlX2FnZSB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfYXJlYSB+IG5vcm1hbCgwLCAxKTsNCiAgDQogIC8vIExpbmVhciBwcmVkaWN0b3INCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfYWdlICogaXNsYW5kX2FnZSArIHNsb3BlX2FyZWEgKiBsb2dfaXNsYW5kX2FyZWE7DQogIA0KICAvLyBNb2RlbA0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhKTsgDQp9DQoNCmdlbmVyYXRlZCBxdWFudGl0aWVzIHsNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX2FnZSAqIGlzbGFuZF9hZ2Vbbl0gKyBzbG9wZV9hcmVhICogbG9nX2lzbGFuZF9hcmVhW25dKTsNCiAgfQ0KfQ0KDQpgYGANCg0KDQojIyMjIFBvc3RlcmlvcnMNCg0KPGJyPg0KPGJyPg0KDQoNCiFbRmlnIDkuIFBhcmFtZXRlciBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9ucyBmb3IgTG9hZCB+IHZlZ2V0YXRpb24gbW9kZWxdKGRfb3V0cHV0L2ZpZ3VyZXMvcG9zdGVyaW9yX3BhcnMvcG9zdGVyaW9yX2lzbGFuZC5wbmcpDQo8YnI+DQo8YnI+DQoNCiMjIyMgUHJlZGljdGl2ZSBhY2N1cmFjeQ0KDQo8YnI+IA0KPGJyPg0KDQohW0ZpZyAxMC4gUHJlZGljdGl2ZSBhY2N1cmFjeSBmb3IgTG9hZCB+IGlzbGFuZCBhZ2UgKyBpc2xhbmQgYXJlYSBtb2RlbF0oZF9vdXRwdXQvZmlndXJlcy9wcmVkaWN0aW9ucy9wcGNfbG9hZF9hZ2VhcmVhLnBuZykNCg0KDQoNCjxicj4gDQo8YnI+DQo8YnI+DQoNCg0KDQojIDIuIFBoeWxvZ2VuZXRpYyBzaWduYWwgb2YgZW5jYXBzdWxhdGlvbnMgaW4gdGhlIE5hZXNpb3R1cyByYWRpYXRpb24NCg0KPGJyPg0KPGJyPg0KDQoNCkRlcGFydHVyaW5nIGZyb20gdGhlIG1vc3QgcmVjZW50IHRyZWUgYnVpbHQgdXNpbmcgUkFEIHNlcSwgd2UgdXNlIHRoZSBSQUQgZGF0YWJhc2UgdG8gYWRkIHRoZSB0aXAgbmFtZXM6DQoNCjxicj4NCg0KIVtGaWcgWC4gSyBzdGF0aXN0aWMgdmFsdWUgaW4gbnVsbCBkaXN0cmlidXRpb25dKGRfb3V0cHV0L2ZpZ3VyZXMvcGh5bG8vdHJlZV9waGlsbGlwcy5wbmcpDQoNCjxicj4NCjxicj4NCg0KDQpXZSBwcnVuZSBpdCB0byBrZWVwIG9ubHkgdGhlIHNwZWNpZXMgd2UgYW5hbHl6ZWQgdGhhdCBtYXRjaCB0aGUgY3VycmVudCBuYW1lczoNCg0KPGJyPg0KDQohW0ZpZyBYLiBLIHN0YXRpc3RpYyB2YWx1ZSBpbiBudWxsIGRpc3RyaWJ1dGlvbl0oZF9vdXRwdXQvZmlndXJlcy9waHlsby9wcnVuZWRfdHJlZS5wbmcpDQoNCjxicj4NCjxicj4NCg0KPiBXZSB1c2UgdGhlICoqcGh5dG9vbHMqKiBwYWNrYWdlIHRvIHRlc3QgZm9yIHBoeWxvZ2VuZXRpYyBzaWduYWwuDQoNCiMjIEtsb21iZXJnJ3MgSw0KDQo8YnI+DQoNClBoeWxvZ2VuZXRpYyBzaWduYWwgSyA6ICoqMi4yMTMxOSoqIA0KTUxFKHNpZzIpIDogNi4yNzY3OGUtMDUgDQpsb2dMKHNpZzIpIDogLTM2LjY0NTYgDQpQLXZhbHVlIChiYXNlZCBvbiAxMDAwIHJhbmRvbWl6YXRpb25zKSA6ICoqMC4wMDEqKiANCg0KPGJyPg0KDQoNCiFbRmlnIFguIEsgc3RhdGlzdGljIHZhbHVlIGluIG51bGwgZGlzdHJpYnV0aW9uXShkX291dHB1dC9maWd1cmVzL3BoeWxvL2tfc3RhdGlzdGljLnBuZykNCg0KPGJyPg0KDQoNClBsb3R0aW5nIHRoZSB0cmFpdCB2YWx1ZSBhbmQgYnJhbmNoZXMgdXNpbmcgKipjb250TWFwKCkqKiBmdW5jdGlvbjoNCg0KPGJyPg0KDQoNCiFbRmlnIFguIEsgc3RhdGlzdGljIHZhbHVlIGluIG51bGwgZGlzdHJpYnV0aW9uXShkX291dHB1dC9maWd1cmVzL3BoeWxvL3BoeWxvX2JyYW5jaF9jb2xvci5wbmcpDQo=